package theMemoryModel;

import org.openjdk.jol.info.ClassLayout;

/**
 * @Author: Jamie Nie
 * @Date: 2021/6/22 14:04
 * @Slogan: The harder you work, the more luck you have.
 * @desc:   计算对象大小
 *
 * 什么是java对象的指针压缩？
 * 1.jdk1.6 update14开始，在64bit操作系统中，JVM支持指针压缩
 * 2.jvm配置参数:UseCompressedOops，compressed--压缩、oop(ordinary object pointer)--对象指针
 * 3.启用指针压缩:-XX:+UseCompressedOops(默认开启)，禁止指针压缩:-XX:-UseCompressedOops
 *
 * 为什么要进行指针压缩？
 * 1.在64位平台的HotSpot中使用32位指针(实际存储用64位)，内存使用会多出1.5倍左右，使用较大指针在主内存和缓存之间移动数据，占用较大宽带，同时GC也会承受较大压力
 * 2.为了减少64位平台下内存的消耗，启用指针压缩功能
 * 3.在jvm中，32位地址最大支持4G内存(2的32次方)，可以通过对对象指针的存入堆内存时压缩编码、取出到cpu寄存器后解码方式进行优化(对象指针在堆中是32位，在寄存器中是35位，2的35次方=32G)，使得jvm只用32位地址就可以支持更大的内存配置(小于等于32G)
 * 4.堆内存小于4G时，不需要启用指针压缩，jvm会直接去除高32位地址，即使用低虚拟地址空间
 * 5.堆内存大于32G时，压缩指针会失效，会强制使用64位(即8字节)来对java对象寻址，这就会出现1的问题，所以堆内存不要大于32G为好
 *
 * 关于对齐填充：对于大部分处理器，对象以8字节整数倍来对齐填充都是最高效的存取方式。
 */
public class JOLSample {

    public static void main(String[] args) {
        ClassLayout classLayout = ClassLayout.parseInstance(new Object());
        System.out.println(classLayout.toPrintable());

        System.out.println();
        ClassLayout classLayout1 = ClassLayout.parseInstance(new int[]{});
        System.out.println(classLayout1.toPrintable());

        System.out.println();
        ClassLayout classLayout2 = ClassLayout.parseInstance(new A());
        System.out.println(classLayout2.toPrintable());

    }

    // -XX:+UseCompressedOops           默认开启的压缩所有指针
    // -XX:+UseCompressedClassPointers  默认开启的压缩对象头里的类型指针Klass Pointer
    // Oops : Ordinary Object Pointers

    public static class A{
                        //8B mark word
                        //4B Klass Pointer 如果关闭压缩-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops，则占用8B
        int id;         //4B
        String name;    //4B 如果关闭指针压缩 -XX:-UseCompressedOops,则占用8B
        byte b;         //1B
        Object o;       //4B 如果关闭指针压缩 -XX:-UseCompressedOops,则占用8B
    }
}
